import {
    FC, ReactNode, useCallback, useRef, useEffect
} from 'react';
import { initShader } from '@utils/utils';
import styles from './image-bg.module.less';

export interface ImageBgProps {
    children?: ReactNode;
}

const ImageBg: FC<ImageBgProps> = () => {
    const canvasRef = useRef(null);

    const main = useCallback(async (canvas: HTMLCanvasElement) => {
        const gl = canvas.getContext('webgl');

        const VERTEX_SHADER_SOURCE = `
            attribute vec4 aPosition;
            attribute vec4 aTex;

            varying vec2 vTex;
            void main() {
                gl_Position = aPosition;
                vTex = vec2(aTex.x, aTex.y);
            }
        `;

        const FRAGMENT_SHADER_SOURCE = `
            precision lowp float;
            // 2d 纹理
            uniform sampler2D uSampler;
            uniform sampler2D uSampler1;
            // 立方纹理
            // uniform sampleCube uSampler;

            varying vec2 vTex;
            void main() {
                vec4 c1 = texture2D(uSampler, vTex);
                vec4 c2 = texture2D(uSampler1, vTex);
                gl_FragColor = c1 * c2;
            }
        `;

        const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE);

        const aPosition = gl.getAttribLocation(program, 'aPosition');
        const aTex = gl.getAttribLocation(program, 'aTex');
        const uSampler = gl.getUniformLocation(program, 'uSampler');
        const uSampler1 = gl.getUniformLocation(program, 'uSampler1');

        const points = new Float32Array([
            -0.5, 0.5, 0.0, 1.0,
            -0.5, -0.5, 0.0, 0.0,
            0.5, 0.5, 1.0, 1.0,
            0.5, -0.5, 1.0, 0.0,
        ]);
        const Bytes = points.BYTES_PER_ELEMENT;
        const pointsBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, pointsBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

        gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, Bytes * 4, 0);
        gl.enableVertexAttribArray(aPosition);
        gl.vertexAttribPointer(aTex, 2, gl.FLOAT, false, Bytes * 4, Bytes * 2);
        gl.enableVertexAttribArray(aTex);

        const imgTexture = (url, u, i) => {
            return new Promise((resolve, reject) => {
                const img = new Image();

                img.onload = () => {
                    const texture = gl.createTexture();

                    // 图片原始坐标轴原点在左上角，但是纹理坐标（st坐标）在右下角，所以需要转换y坐标
                    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
                    // 开启纹理单元，通过纹理单元管理纹理对象，每个纹理单元管理一张纹理图像
                    gl.activeTexture(gl[`TEXTURE${i}`]);

                    // 绑定纹理对象
                    gl.bindTexture(gl.TEXTURE_2D, texture);

                    // 处理放大缩小逻辑
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                    // 横向 纵向 平铺方式
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

                    // 配置纹理图像
                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
                    gl.uniform1i(u, i);
                    resolve(null);
                };

                img.src = url;
            });
        };

        Promise.all([
            imgTexture('/demo.jpg', uSampler, 0),
            imgTexture('/logo.png', uSampler1, 1)
        ]).then(() => {
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        });
        return () => {
            console.log('remove');
        };
    }, []);

    useEffect(() => {
        let removeEvent = null;
        if (canvasRef.current) {
            removeEvent = main(canvasRef.current);
        }

        return () => {
            if (typeof removeEvent === 'function') {
                removeEvent?.();
            }
        };
    }, [main]);

    return (
        <div className={styles.imageBg}>
            <canvas ref={canvasRef} width="600" height="400" />
        </div>
    );
};

export default ImageBg;
